/*
*  Copyright (C) 2009  Peter Kist & Jan Ripke
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "MenuManager.h"

#include <Util/Logger.h>
#include <Core/Kernel/AppContext.h>
#include <Modules/Gfx/Ogre/Types.h>
#include <Modules/Gfx/Ogre/Manager.h>
#include <Modules/Gfx/Ogre/Gui/MenuFactory.h>
#include <Modules/Gfx/Ogre/Gui/Menu.h>
#include <Modules/Gfx/Ogre/Gui/Injector.h>
#include <Core/Interface/Input.h>

#include <OgreException.h>
#include <OgreRoot.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>

#include <CEGUIDefaultLogger.h>
#include <CEGUISystem.h>
#include <CEGUIRenderer.h>
#include <CEGUISchemeManager.h>
#include <CEGUIFontManager.h>
#include <CEGUIString.h>
#include <CEGUIInputEvent.h>

#include <RendererModules/Ogre/CEGUIOgreRenderer.h>
//#include <OgreCEGUIRenderer.h>


namespace galaxy {
    namespace gfx {
        namespace ogre3d {
            namespace gui {

                MenuManager::MenuManager(Manager& manager)
                {
                    m_Manager = &manager;
                    m_CEGUIRenderer = 0L;
                    m_GuiInjector = 0L;
                    m_Initialized = false;
                }

                MenuManager::~MenuManager(void)
                {
                    if (m_GuiInjector) {
                        delete m_GuiInjector;
                    }
                    if (m_CEGUIRenderer) {
                        m_CEGUIRenderer->destroySystem();
                    }
                }

                bool MenuManager::initialize () {
                    Ogre::Root * root = m_Manager->getRoot ();
                    if (! root) return false;

                    galaxy::AppContext& context = galaxy::AppContext::singleton();

                    try {
                        ::Ogre::SceneManager *ogreMgr = root->getSceneManager("Default SceneManager");
                        ::Ogre::RenderWindow *ogreWin = root->getAutoCreatedWindow();

                        CEGUI::OgreRenderer& renderer = CEGUI::OgreRenderer::bootstrapSystem ();

                        m_GuiInjector = new Injector (CEGUI::System::getSingleton());

                        CEGUI::SchemeManager::getSingleton().create("TaharezLook.scheme");
                        CEGUI::System::getSingleton().setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook",
                            (CEGUI::utf8*)"MouseArrow");

                        //CEGUI::FontManager::getSingleton().createFont("flotsam-10.font");
                        CEGUI::System::getSingleton().setDefaultFont((CEGUI::utf8*)"Flotsam-10");

                        // set the mouse cursor initially in the middle of the screen
                        CEGUI::System::getSingleton().injectMousePosition((float)ogreWin->getWidth() / 2.0f,
                            (float)ogreWin->getHeight() / 2.0f);

                    } catch (Ogre::Exception& e) {
                        LOG_ERROR ("CEGUI initialization failed");
                        LOG_ERROR (e.what ());
                        return false;
                    } catch (std::exception& e) {
                        LOG_ERROR ("CEGUI initialization failed");
                        LOG_ERROR (e.what ());
                        return false;
                    }

                    m_Initialized = true;
                    return true;
                }

                /** Creates a new menu window. The menu window is put in the m_NewMenu member so that the
                * main gfx thread can pick it up. It is not directly changed in CEGUI since that will most
                * likely crash the gfx thread.
                */
                bool MenuManager::changeMenu (gfx::Menu::Name& menuName) {
                    try {
                        LOG_TRACE (std::string("changing menu to ") + menuName);

                        if (! m_Initialized) {
                            if (initialize () == false) return false;
                        }

                        if (m_CurrentMenu) {
                            m_CurrentMenu->unload ();
                            m_CurrentMenu.reset ();
                        }

                        m_CurrentMenu = MenuFactory::createMenu (*this, menuName);
                        if (m_CurrentMenu) {
                            m_CurrentMenu->load ();
                            m_CurrentMenu->setup ();    // setup event handlers for buttons, etc...
                            CEGUI::System::getSingleton().setGUISheet (m_CurrentMenu->getWindow());
                        }

                    } catch (Ogre::FileNotFoundException& e) {
                        Ogre::String p = e.getDescription();
                    } catch (Ogre::Exception& e) {
                        Ogre::String p2 = e.getDescription();
                    } catch (std::exception& e) {
                        const char * p3 = e.what();
                    }   
                    return true;
                }

                /** Hide the currently shown menu window. 
                */
                bool MenuManager::hideMenu () {
                    try {
                        LOG_TRACE (std::string("hiding menu: ") + 
                            (m_CurrentMenu ? m_CurrentMenu->menuName () : "<no menu shown>"));

                        if (! m_Initialized) {
                            if (initialize () == false) {
                                return false;
                            }
                        }

                        if (m_CurrentMenu) {
                            m_CurrentMenu->unload ();
                            m_CurrentMenu.reset ();
                        }

                        CEGUI::System::getSingleton().setGUISheet (0L);

                    } catch (Ogre::FileNotFoundException& e) {
                        Ogre::String p = e.getDescription();
                    } catch (Ogre::Exception& e) {
                        Ogre::String p2 = e.getDescription();
                    } catch (std::exception& e) {
                        const char * p3 = e.what();
                    }

                    return true;
                }

                bool MenuManager::handleMouseEvent (input::MouseEvent& event) {

                    switch (event.subtype()) {
                        case MODULE_SUBTYPE_INPUT_MOUSEMOVE: 
                            {
								float x = static_cast<float>(event.m_Xrel);
								float y = static_cast<float>(event.m_Yrel);
                                m_GuiInjector->injectMouseMove (x, y);
                                break;
                            }
                        case MODULE_SUBTYPE_INPUT_MOUSEPRESS:
                            {
                                m_GuiInjector->injectMouseButtonDown (event.m_MouseButton);
                                break;
                            }
                        case MODULE_SUBTYPE_INPUT_MOUSERELEASE:
                            {
                                m_GuiInjector->injectMouseButtonUp (event.m_MouseButton);
                                break;
                            }
                        default:
                            return false; // unsupported action
                    }

                    return true;
                }

                bool MenuManager::handleKeyEvent (input::KeyEvent& event) {
                    return true;
                }

            } // namespace gui
        } // namespace ogre3d
    } // namespace gfx
} // namespace galaxy
